#include <getopt.h>
#include <string.h>
#include <rtthread.h>
#include <aic_core.h>
#include <stdlib.h>
#include <sys/time.h>
#include "hal_adcim.h"
#include "rtdevice.h"
#include "aic_log.h"
#include "hal_gpai.h"
#include <stdio.h>
#include "aic_hal_gpio.h"


#define SAMPLE_UART_NAME    "uart3"                 // 串口设备名称
#define RCV_BUFF_SIZE_MAX   1024                    // 接收最大字节长度

static struct rt_semaphore rx_sem;                  // 用于接收消息的信号量
static rt_device_t serial;                          // 串口设备句柄
static rt_thread_t serial_recv_thread;              // 串口接收线程句柄

static char serial_recv_buff[RCV_BUFF_SIZE_MAX];    // 串口接收缓存区
static char serial_recv_flag;                       // 串口接收标志
static int  serial_recv_length;                     // 接收字节长度


//
/* 消息队列控制块 */
extern struct rt_messagequeue oled_mq;
/* 消息队列中用到的放置消息的内存池 */
extern rt_uint8_t oled_msg_pool[2048];
//


/* 新增结构体定义（放在文件开头）*/
#pragma pack(1) // 按1字节对齐
typedef struct {
    uint8_t header;      // 0xAA
    uint8_t length;      // 数据长度
    uint8_t cmd;         // 0x20
    uint8_t sign_unit;   // 正负+单位
    uint8_t decimal;     // 小数位
    uint32_t net_weight; // 大端格式净重
    uint8_t stable;      // 稳定状态
    uint8_t tare[3];     // 3字节皮重
    uint8_t checksum;    // 校验码
    uint8_t footer;      // 0x2F
} WeightProtocol;
#pragma pack()
/* 新增解析函数 */


// 定义一个静态函数，用于解析重量协议数据包
static void parse_weight_protocol(uint8_t *data, int len) 
{
    // 检查数据包长度是否小于WeightProtocol结构体的大小
    if (len < sizeof(WeightProtocol)) {
        // 如果长度不足，打印错误信息并返回
        rt_kprintf("Error: 长度不足 Invalid packet length\n");
        return;
    }

    // 将传入的数据转换为WeightProtocol结构体指针
    WeightProtocol *pkt = (WeightProtocol *)data;
    
    /* 基础校验 */
    // 检查数据包的头部和尾部是否符合预期
    if (pkt->header != 0xAA || pkt->footer != 0x2F) {
        // 如果头部或尾部不匹配，打印错误信息并返回
        rt_kprintf("Error: Header/Footer mismatch,头尾错误\n");
        return;
    }

    // /* 校验和验证 */
    // uint8_t calc_checksum = 0; // 初始化计算校验和
    // for (int i = 0; i < sizeof(WeightProtocol)-2; i++) { // 跳过checksum和footer
    //     calc_checksum += data[i];//计算校验和
    // }
    // if (calc_checksum != pkt->checksum) {//判断校验
    //     rt_kprintf("Error: Checksum failed (Recv:0x%02X Calc:0x%02X)\n", 
    //               pkt->checksum, calc_checksum);
    //     return;
    // }

    /* 解析有效数据 */
    // 符号由最高位决定（bit7）
    char sign = (pkt->sign_unit & 0x80) ? '+' : '-';

    // 单位由低7位决定（bit0~bit6）
    const char *unit = "??";
    switch (pkt->sign_unit & 0x7F) 
    { // 掩码取低7位
        case 0x01: unit = "KG"; break;
        case 0x02: unit = "LB"; break;
        default:   unit = "??"; break; // 未知单位处理
    }

    // 将net_weight从大端序转换为主机序
    uint32_t net_weight = (pkt->net_weight >> 24) | 
                         ((pkt->net_weight >> 8) & 0xFF00) |
                         ((pkt->net_weight << 8) & 0xFF0000) |
                         (pkt->net_weight << 24); // 大端转主机序
    
    float net_val = (float)net_weight / pow(10, pkt->decimal);
    
    /* 格式化输出 */
    // 定义一个字符数组output，用于存储格式化后的字符串，大小为128个字符
    char output[128];
    // 使用snprintf函数将格式化的字符串写入output数组
    // snprintf的第一个参数是目标字符数组，第二个参数是目标数组的大小
    // 后续的参数是格式化字符串和对应的变量
    snprintf(output, sizeof(output), 
            // 格式化字符串，包含多个占位符
            "Net: %c%.2f %s | Stable: %s | Tare: %d", 
            sign, net_val, unit,
            (pkt->stable == 0x0A) ? "Yes" : "No",//判断稳定状态
            (pkt->tare[0] << 16) | (pkt->tare[1] << 8) | pkt->tare[2]);//计算皮重
    
    rt_kprintf("Data=%s\n", output);
}


/* ====================串口发送和打印线程=================== */

#define THREAD_PRIORITY         25      // 线程优先级
#define THREAD_STACK_SIZE       4096    // 线程大小
#define THREAD_TIMESLICE        20      // 时间片

static rt_thread_t serial_thread = RT_NULL;   // 线程控制块


// 中断接收回调函数
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口有数据传入后产生中断，调用此回调函数，释放信号量 */
    if (size > 0)
        rt_sem_release(&rx_sem);

    return RT_EOK;
}

// 串口接收线程入口函数
static void serial_recv_thread_entry(void *param)
{
    rt_kprintf("\nserial_recv_thread_entry run ......\n");
    while(1)
    {
        char temp_recv_buff = 0; // 接收临时缓存区
        int ret = rt_device_read(serial, 0, &temp_recv_buff, 1);
        if(ret < 0) // 出现了错误
        {
            pr_debug("read() return [%ld] %s\n", rt_get_errno(), rt_strerror(rt_get_errno()));
        }
        if(ret == 0) // 未接到数据
        {
            // 重置信号量
            rt_sem_control(&rx_sem, RT_IPC_CMD_RESET, RT_NULL);
            // 获取信号量，如果没有获取得到则阻塞在这里永远等待。
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }

        if(ret == 1) // 接收到1字节的数据
        {
            // 防止数据超出缓存区的大小
            if(serial_recv_length < RCV_BUFF_SIZE_MAX - 1)
            {
                // 存入接收缓存区并递增长度
                serial_recv_buff[serial_recv_length++] = temp_recv_buff;
                // rt_kprintf("%x\n", temp_recv_buff); // 打印接收到的字节，用于调试
            }
            else
            {
                // 如果缓冲区已满，则从0开始覆盖旧数据
                serial_recv_length = 0;
                serial_recv_buff[serial_recv_length++] = temp_recv_buff;
            }
            // 为接收缓存区最后添加 '\0'
            serial_recv_buff[serial_recv_length] = '\0';
            // 设置串口接收完成标志
            serial_recv_flag = 1;
        }
    }
}

/************************************************
函数名称 ： Clear_recv_buff
功    能 ： 清空串口接收缓存区
参    数 ： 无
返 回 值 ：
作    者 ： LC
*************************************************/
static void Clear_recv_buff(void)
{
    // 清空接收缓存区
    rt_memset(serial_recv_buff, 0, sizeof(serial_recv_buff));

    // 清空标志位
    serial_recv_flag = 0;

    // 清空缓存区长度计量
    serial_recv_length = 0;
}

/************************************************
函数名称 ： serial_send_byte
功    能 ： 串口发送一个字节
参    数 ： 发送的数据
返 回 值 ： RT_EOK成功   -RT_ERROR失败
作    者 ： LC
*************************************************/
static int Serial_Send_Byte(uint8_t dat)
{
    int ret = rt_device_write(serial, 0, &dat, 1);
    if(ret != 1)
    {
        LOG_E("Failed to [Serial_Send_Byte] code[%d] !!!", ret);
        return -RT_ERROR;
    }

    return RT_EOK;
}

/************************************************
函数名称 ： Serial_Send_String
功    能 ： 串口发送字符串
参    数 ： data_buff缓存区地址
返 回 值 ： RT_EOK成功   -RT_ERROR失败
作    者 ： LCKFB
*************************************************/
static int Serial_Send_String(uint8_t *data_buff)
{
    int err_count = 0;

    /* 地址为空 或者 值为空 跳出 */
    while(data_buff && *data_buff)
    {
        if(RT_EOK != Serial_Send_Byte(*data_buff++))
        {
            err_count++;
            continue;
        }
    }

    /* 如果err_count不为0，则说明发送的时候有错误！！！ */
    if(err_count)
    {
        LOG_E("serial_send_string failed !!!");
        return -RT_ERROR;
    }

    return RT_EOK;
}

/******************************************************************
 * 函 数 名 称：Serial_Recv_DATA
 * 函 数 说 明：接串口的数据
 * 函 数 形 参：data_buff数据缓存区
 * 函 数 返 回： 0：  未接收到数据
 *             其他： 接收到的数据长度
 * 作       者：LCKFB
 * 备       注：无
******************************************************************/
int Serial_Recv_DATA(uint8_t *data_buff)
{
    int i;

    /* 判断是否接到了数据 */
    if((serial_recv_flag != 1) || (serial_recv_length == 0))
    {
        /* 未接到 */
        return 0;
    }

    /* 将数据转存到指针指向的地址中 */
    for(i = 0; i < serial_recv_length; i++)
    {
        data_buff[i] = serial_recv_buff[i];
    }

    /* 加入字符串结尾 */
    data_buff[i] = '\0';

    /* 清除接收的数据、标志位和数据长度。 */
    Clear_recv_buff();

    return i; // 返回接收到的数据长度
}

/************************************************
函数名称 ： UART_Init
功    能 ： 串口初始化
参    数 ： 无
返 回 值 ： RT_EOK成功   -RT_ERROR失败
作    者 ： LCKFB
*************************************************/
static int UART_Init(void)
{
    int ret = 0;

    // 清空接收缓存区
    rt_memset(serial_recv_buff,0,sizeof(serial_recv_buff));

    // 清空标志位
    serial_recv_flag = 0;

    // 清空缓存区长度计量
    serial_recv_length = 0;

    rt_kprintf("Try to open(%s)\n", SAMPLE_UART_NAME);

    // 获取串口句柄
    serial = rt_device_find(SAMPLE_UART_NAME);
    if (!serial)
    {
        LOG_E("find %s failed!\n", SAMPLE_UART_NAME);

        return -RT_ERROR;
    }

    // 初始化信号量
    ret = rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    if (ret != RT_EOK)
    {
        LOG_E("failed to rt_sem_init !\n");
        return -RT_ERROR;
    }

    // 打开串口设备
    ret = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    if (ret != RT_EOK)
    {
        LOG_E("open %s failed : %d !\n", SAMPLE_UART_NAME, ret);
        return -RT_ERROR;
    }

    // 设置接收回调函数
    rt_device_set_rx_indicate(serial, uart_input);

    // 创建串口数据接收线程
    serial_recv_thread = rt_thread_create("serial", serial_recv_thread_entry, RT_NULL, 1024*2, 15, 20);
    if (serial_recv_thread != RT_NULL)
    {
        // 启动线程
        rt_thread_startup(serial_recv_thread);
    }
    else
    {
        rt_device_close(serial);
        LOG_E("Failed to [rt_thread_create] !!!");
        return -RT_ERROR;
    }

    return RT_EOK;
}
#include <oled.h>

// 线程入口函数// 修改serial3_thread_entry函数
static void serial3_thread_entry(void *param)
{
  // 定义一个无符号8位整数变量run_time，用于记录运行时间
  uint8_t run_time = 0;
  // 无限循环，程序会一直运行在这个循环中
    while(1) {
      // 每次循环run_time加1，用于记录循环次数或时间
        run_time++;
      // 定义一个无符号8位整数数组recv_buff，大小为256，用于存储接收到的数据，并初始化为0
        uint8_t recv_buff[256] = {0};
      // 调用Serial_Recv_DATA函数接收数据，接收到的数据存储在recv_buff中，返回接收到的数据个数
        int count = Serial_Recv_DATA(recv_buff);

      // 如果接收到的数据个数大于0，表示有数据接收成功
        if (count > 0) {
            /* 原始数据打印（调试用） */
            rt_kprintf("Raw: ");
            for(int i=0; i<count; i++) {
                rt_kprintf("%02X ", recv_buff[i]);
            }
            rt_kprintf("\n");
            
            /* 协议解析 */
            parse_weight_protocol(recv_buff, count);
            
        }
        rt_thread_mdelay(20); // 缩短延迟提高响应速度
    }
}


// 数据发送函数
static void send_demoData(int argc, char **argv)
{
    static int num = 1;
    uint8_t Send_Buff[128] = {"立创·衡山派D133EBS开发板 * UART框架使用测试"};
    int ret = 0;
    char buffer[128] = {0};

    // 使用 snprintf 来格式化要发送的字符串Send_Buff
    snprintf(buffer, sizeof(buffer), "【%d】%s", num, (argc == 2) ? *(argv+1) : (char *)Send_Buff);

    // 发送数据
    ret = Serial_Send_String((uint8_t *)buffer);

    if(ret != RT_EOK)
    {
        LOG_E("%s: The test data transmission failed.", __FUNCTION__);
    }
    else
    {
        rt_kprintf("\n[%d] Send success\n", num);
        num++; // 只有发送成功时才递增 num
    }
}

// 导出函数为命令
MSH_CMD_EXPORT(send_demoData, Send test data);

// 串口接收和发送线程开启
static void uart3_test_on(int argc, char **argv)
{
    int ret = UART_Init();  // 串口初始化
    if(ret != RT_EOK)
    {
        LOG_E("Failed to [UART_Init] !!!");
        LOG_E("file: %s line: %d", __FILE__, __LINE__);
        return;
    }
    rt_kprintf("UART3_Init OK!!\n");

    /* 创建线程，名称是 serial3_thread，入口是 serial3_thread_entry */
    serial_thread = rt_thread_create("serial3_thread",
                            serial3_thread_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);

    /* 如果获得线程控制块，启动这个线程 */
    if (serial_thread != RT_NULL)
        rt_thread_startup(serial_thread);

    rt_kprintf("Test transmission and reception using UART3 serial port!!\n");
}

// //使用命令开启线程// 导出函数为命令
// MSH_CMD_EXPORT(uart3_test_on, Test transmission and reception using UART3 serial port);

// 导出函数自动运行，在系统初始化时调用uart3_test_on函数
INIT_APP_EXPORT(uart3_test_on);